/*-------------------------------------------------------------------------
 *
 * parse_agg.c
 *	  处理解析器中的聚合和窗口函数
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/parser/parse_agg.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "catalog/pg_aggregate.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_agg.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"


typedef struct
{
	ParseState *pstate;
	int			min_varlevel;
	int			min_agglevel;
	int			sublevels_up;
} check_agg_arguments_context;

typedef struct
{
	ParseState *pstate;
	Query	   *qry;
	bool		hasJoinRTEs;
	List	   *groupClauses;
	List	   *groupClauseCommonVars;
	bool		have_non_var_grouping;
	List	  **func_grouped_rels;
	int			sublevels_up;
	bool		in_agg_direct_args;
} check_ungrouped_columns_context;

static int	fc_check_agg_arguments(ParseState *fc_pstate,
								List *fc_directargs,
								List *fc_args,
								Expr *fc_filter);
static bool fc_check_agg_arguments_walker(Node *fc_node,
									   check_agg_arguments_context *fc_context);
static void fc_check_ungrouped_columns(Node *fc_node, ParseState *fc_pstate, Query *fc_qry,
									List *fc_groupClauses, List *fc_groupClauseCommonVars,
									bool fc_have_non_var_grouping,
									List **fc_func_grouped_rels);
static bool fc_check_ungrouped_columns_walker(Node *fc_node,
										   check_ungrouped_columns_context *fc_context);
static void fc_finalize_grouping_exprs(Node *fc_node, ParseState *fc_pstate, Query *fc_qry,
									List *fc_groupClauses, bool fc_hasJoinRTEs,
									bool fc_have_non_var_grouping);
static bool fc_finalize_grouping_exprs_walker(Node *fc_node,
										   check_ungrouped_columns_context *fc_context);
static void fc_check_agglevels_and_constraints(ParseState *fc_pstate, Node *fc_expr);
static List *fc_expand_groupingset_node(GroupingSet *fc_gs);
static Node *fc_make_agg_arg(Oid fc_argtype, Oid fc_argcollation);


/*
 * transformAggregateCall -
 *		完成聚合调用的初始转换
 *
 * parse_func.c 已识别该函数为聚合，并设置了
 * Aggref 的所有字段，除了 aggargtypes、aggdirectargs、args、
 * aggorder、aggdistinct 和 agglevelsup。传递的 args 列表经过
 * 标准表达式转换和类型强制以匹配 agg 的声明参数类型，
 * 而传递的 aggorder 列表根本没有被转换。
 *
 * 在这里，我们将 args 列表分为直接参数和聚合参数，
 * 将前者存储在 agg->aggdirectargs 中，后者存储在 agg->args。
 * 常规参数（但不是直接参数）通过插入 TargetEntry 节点转换为
 * targetlist。然后我们将 aggorder 和 agg_distinct
 * 规范转换为生成 agg->aggorder 和 agg->aggdistinct 的 SortGroupClause 节点列表。
 * （对于常规聚合，这可能会导致将 resjunk 表达式添加到
 * targetlist；但对于有序集合聚合，aggorder 列表总是与聚合
 * 参数一一对应。）
 *
 * 我们还必须确定聚合实际属于哪个查询级别，
 * 相应地设置 agglevelsup，并在相应的
 * pstate 级别中标记 p_hasAggs 为 true。
 */
void transformAggregateCall(ParseState *fc_pstate, Aggref *fc_agg,
					   List *fc_args, List *fc_aggorder, bool fc_agg_distinct)
{
	List	   *fc_argtypes = NIL;
	List	   *fc_tlist = NIL;
	List	   *fc_torder = NIL;
	List	   *fc_tdistinct = NIL;
	AttrNumber	fc_attno = 1;
	int			fc_save_next_resno;
	ListCell   *fc_lc;

	if (AGGKIND_IS_ORDERED_SET(fc_agg->aggkind))
	{
		/*
		 * 对于有序集合聚合，args 列表包含直接参数和
		 * 聚合参数；我们必须将它们分开。
		 */
		int			fc_numDirectArgs = list_length(fc_args) - list_length(fc_aggorder);
		List	   *fc_aargs;
		ListCell   *fc_lc2;

		Assert(fc_numDirectArgs >= 0);

		fc_aargs = list_copy_tail(fc_args, fc_numDirectArgs);
		fc_agg->aggdirectargs = list_truncate(fc_args, fc_numDirectArgs);

		/*
		 * 从聚合参数构建一个目标列表，并为每个参数
		 * 制作一个排序列表条目。请注意，SortBy 节点中的
		 * 表达式被忽略（它们是转换后参数的原始版本）；我们
		 * 只是查看 SortBy 节点中的排序信息。
		 */
		forboth(fc_lc, fc_aargs, fc_lc2, fc_aggorder)
		{
			Expr	   *fc_arg = (Expr *) lfirst(fc_lc);
			SortBy	   *fc_sortby = (SortBy *) lfirst(fc_lc2);
			TargetEntry *fc_tle;

			/* 我们不在乎为条目分配列名 */
			fc_tle = makeTargetEntry(fc_arg, fc_attno++, NULL, false);
			fc_tlist = lappend(fc_tlist, fc_tle);

			fc_torder = addTargetToSortList(fc_pstate, fc_tle,
										 fc_torder, fc_tlist, fc_sortby);
		}

		/* 在有序集合聚合中绝对没有任何 DISTINCT */
		Assert(!fc_agg_distinct);
	}
	else
	{
		/* 常规聚合，因此没有直接参数 */
		fc_agg->aggdirectargs = NIL;

		/*
		 * 将Exprs的普通列表转换为目标列表。
		 */
		foreach(fc_lc, fc_args)
		{
			Expr	   *fc_arg = (Expr *) lfirst(fc_lc);
			TargetEntry *fc_tle;

			/* 我们不在乎为条目分配列名 */
			fc_tle = makeTargetEntry(fc_arg, fc_attno++, NULL, false);
			fc_tlist = lappend(fc_tlist, fc_tle);
		}

		/*
		 * 如果我们有ORDER BY，进行转换。如果这些列出现在
		 * ORDER BY中，但在参数列表中没有，将向tlist添加列。
		 * 它们将被标记为resjunk = true，以便我们稍后能够与
		 * 常规聚合参数区分。
		 *
		 * 我们需要处理p_next_resno，因为它将用于编号
		 * 任何新的目标列表条目。
		 */
		fc_save_next_resno = fc_pstate->p_next_resno;
		fc_pstate->p_next_resno = fc_attno;

		fc_torder = transformSortClause(fc_pstate,
									 fc_aggorder,
									 &fc_tlist,
									 EXPR_KIND_ORDER_BY,
									 true /* 强制SQL99规则 */ );

		/*
		 * 如果我们有DISTINCT，将其转换为生成distinctList。
		 */
		if (fc_agg_distinct)
		{
			fc_tdistinct = transformDistinctClause(fc_pstate, &fc_tlist, fc_torder, true);

			/*
			 * 如果仍然添加了对聚合的哈希区分的执行支持，则移除此检查。
			 */
			foreach(fc_lc, fc_tdistinct)
			{
				SortGroupClause *fc_sortcl = (SortGroupClause *) lfirst(fc_lc);

				if (!OidIsValid(fc_sortcl->sortop))
				{
					Node	   *fc_expr = get_sortgroupclause_expr(fc_sortcl, fc_tlist);

					ereport(ERROR,
							(errcode(ERRCODE_UNDEFINED_FUNCTION),
							 errmsg("could not identify an ordering operator for type %s",
									format_type_be(exprType(fc_expr))),
							 errdetail("Aggregates with DISTINCT must be able to sort their inputs."),
							 parser_errposition(fc_pstate, exprLocation(fc_expr))));
				}
			}
		}

		fc_pstate->p_next_resno = fc_save_next_resno;
	}

	/* 使用转换结果更新Aggref */
	fc_agg->args = fc_tlist;
	fc_agg->aggorder = fc_torder;
	fc_agg->aggdistinct = fc_tdistinct;

	/*
	 * 现在通过直接和聚合参数的类型OID构建aggargtypes列表，
	 * 忽略可能已通过ORDER BY/DISTINCT处理添加的
	 * 任何resjunk条目。我们不能在早些时候执行此操作，
	 * 因为上述处理可能修改一些参数的数据类型，尤其是
	 * 通过解析先前未解析的"unknown"字面量。
	 */
	foreach(fc_lc, fc_agg->aggdirectargs)
	{
		Expr	   *fc_arg = (Expr *) lfirst(fc_lc);

		fc_argtypes = lappend_oid(fc_argtypes, exprType((Node *) fc_arg));
	}
	foreach(fc_lc, fc_tlist)
	{
		TargetEntry *fc_tle = (TargetEntry *) lfirst(fc_lc);

		if (fc_tle->resjunk)
			continue;			/* 忽略垃圾 */
		fc_argtypes = lappend_oid(fc_argtypes, exprType((Node *) fc_tle->expr));
	}
	fc_agg->aggargtypes = fc_argtypes;

	fc_check_agglevels_and_constraints(fc_pstate, (Node *) fc_agg);
}

/*
 * transformGroupingFunc
 *		转换GROUPING表达式
 *
 * GROUPING()的行为类似于聚合。处理层级和嵌套
 * 的方式与聚合相同。我们也为这些表达式设置p_hasAggs。
 */
Node * transformGroupingFunc(ParseState *fc_pstate, GroupingFunc *fc_p)
{
	ListCell   *fc_lc;
	List	   *fc_args = fc_p->args;
	List	   *fc_result_list = NIL;
	GroupingFunc *fc_result = makeNode(GroupingFunc);

	if (list_length(fc_args) > 31)
		ereport(ERROR,
				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
				 errmsg("GROUPING must have fewer than 32 arguments"),
				 parser_errposition(fc_pstate, fc_p->location)));

	foreach(fc_lc, fc_args)
	{
		Node	   *fc_current_result;

		fc_current_result = transformExpr(fc_pstate, (Node *) lfirst(fc_lc), fc_pstate->p_expr_kind);

		/* 表达式的可接受性稍后检查 */

		fc_result_list = lappend(fc_result_list, fc_current_result);
	}

	fc_result->args = fc_result_list;
	fc_result->location = fc_p->location;

	fc_check_agglevels_and_constraints(fc_pstate, (Node *) fc_result);

	return (Node *) fc_result;
}

/*
 * 聚合函数和分组操作（在规范中合并为 <set function specification>）在级别和嵌套限制方面非常相似（尽管我们允许的内容远比规范多）。
 * 将这些限制集中在这里。
 */
static void fc_check_agglevels_and_constraints(ParseState *fc_pstate, Node *fc_expr)
{
	List	   *fc_directargs = NIL;
	List	   *fc_args = NIL;
	Expr	   *fc_filter = NULL;
	int			fc_min_varlevel;
	int			fc_location = -1;
	Index	   *fc_p_levelsup;
	const char *fc_err;
	bool		fc_errkind;
	bool		fc_isAgg = IsA(fc_expr, Aggref);

	if (fc_isAgg)
	{
		Aggref	   *fc_agg = (Aggref *) fc_expr;

		fc_directargs = fc_agg->aggdirectargs;
		fc_args = fc_agg->args;
		fc_filter = fc_agg->aggfilter;
		fc_location = fc_agg->location;
		fc_p_levelsup = &fc_agg->agglevelsup;
	}
	else
	{
		GroupingFunc *fc_grp = (GroupingFunc *) fc_expr;

		fc_args = fc_grp->args;
		fc_location = fc_grp->location;
		fc_p_levelsup = &fc_grp->agglevelsup;
	}

	/*
	 * 检查参数以计算聚合的级别并检测不当的嵌套。
	 */
	fc_min_varlevel = fc_check_agg_arguments(fc_pstate,
									   fc_directargs,
									   fc_args,
									   fc_filter);

	*fc_p_levelsup = fc_min_varlevel;

	/* 将正确的 pstate 级别标记为具有聚合 */
	while (fc_min_varlevel-- > 0)
		fc_pstate = fc_pstate->parentParseState;
	fc_pstate->p_hasAggs = true;

	/*
	 * 检查聚合函数在其聚合查询中的无效位置。
	 *
	 * 为简洁起见，我们支持两种方案来报告错误：将 "err" 设置为自定义消息，或者如果错误上下文足够由 ParseExprKindName 返回的内容标识，则将 "errkind" 设置为 true，*并且* 返回的仅仅是一个 SQL 关键字。（否则，使用自定义消息以避免产生翻译问题。）
	 */
	fc_err = NULL;
	fc_errkind = false;
	switch (fc_pstate->p_expr_kind)
	{
		case EXPR_KIND_NONE:
			Assert(false);		/* 不能发生 */
			break;
		case EXPR_KIND_OTHER:

			/*
			 * 在此接受聚合/分组；调用者必须在需要时抛出错误
			 */
			break;
		case EXPR_KIND_JOIN_ON:
		case EXPR_KIND_JOIN_USING:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in JOIN conditions");
			else
				fc_err = _("grouping operations are not allowed in JOIN conditions");

			break;
		case EXPR_KIND_FROM_SUBSELECT:

			/*
			 * 聚合/分组范围规则使得在此显式声明是值得的
			 */
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in FROM clause of their own query level");
			else
				fc_err = _("grouping operations are not allowed in FROM clause of their own query level");

			break;
		case EXPR_KIND_FROM_FUNCTION:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in functions in FROM");
			else
				fc_err = _("grouping operations are not allowed in functions in FROM");

			break;
		case EXPR_KIND_WHERE:
			fc_errkind = true;
			break;
		case EXPR_KIND_POLICY:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in policy expressions");
			else
				fc_err = _("grouping operations are not allowed in policy expressions");

			break;
		case EXPR_KIND_HAVING:
			/* 可以 */
			break;
		case EXPR_KIND_FILTER:
			fc_errkind = true;
			break;
		case EXPR_KIND_WINDOW_PARTITION:
			/* 可以 */
			break;
		case EXPR_KIND_WINDOW_ORDER:
			/* 可以 */
			break;
		case EXPR_KIND_WINDOW_FRAME_RANGE:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in window RANGE");
			else
				fc_err = _("grouping operations are not allowed in window RANGE");

			break;
		case EXPR_KIND_WINDOW_FRAME_ROWS:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in window ROWS");
			else
				fc_err = _("grouping operations are not allowed in window ROWS");

			break;
		case EXPR_KIND_WINDOW_FRAME_GROUPS:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in window GROUPS");
			else
				fc_err = _("grouping operations are not allowed in window GROUPS");

			break;
		case EXPR_KIND_SELECT_TARGET:
			/* 可以 */
			break;
		case EXPR_KIND_INSERT_TARGET:
		case EXPR_KIND_UPDATE_SOURCE:
		case EXPR_KIND_UPDATE_TARGET:
			fc_errkind = true;
			break;
		case EXPR_KIND_MERGE_WHEN:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in MERGE WHEN conditions");
			else
				fc_err = _("grouping operations are not allowed in MERGE WHEN conditions");

			break;
		case EXPR_KIND_GROUP_BY:
			fc_errkind = true;
			break;
		case EXPR_KIND_ORDER_BY:
			/* 可以 */
			break;
		case EXPR_KIND_DISTINCT_ON:
			/* 可以 */
			break;
		case EXPR_KIND_LIMIT:
		case EXPR_KIND_OFFSET:
			fc_errkind = true;
			break;
		case EXPR_KIND_RETURNING:
			fc_errkind = true;
			break;
		case EXPR_KIND_VALUES:
		case EXPR_KIND_VALUES_SINGLE:
			fc_errkind = true;
			break;
		case EXPR_KIND_CHECK_CONSTRAINT:
		case EXPR_KIND_DOMAIN_CHECK:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in check constraints");
			else
				fc_err = _("grouping operations are not allowed in check constraints");

			break;
		case EXPR_KIND_COLUMN_DEFAULT:
		case EXPR_KIND_FUNCTION_DEFAULT:

			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in DEFAULT expressions");
			else
				fc_err = _("grouping operations are not allowed in DEFAULT expressions");

			break;
		case EXPR_KIND_INDEX_EXPRESSION:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in index expressions");
			else
				fc_err = _("grouping operations are not allowed in index expressions");

			break;
		case EXPR_KIND_INDEX_PREDICATE:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in index predicates");
			else
				fc_err = _("grouping operations are not allowed in index predicates");

			break;
		case EXPR_KIND_STATS_EXPRESSION:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in statistics expressions");
			else
				fc_err = _("grouping operations are not allowed in statistics expressions");

			break;
		case EXPR_KIND_ALTER_COL_TRANSFORM:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in transform expressions");
			else
				fc_err = _("grouping operations are not allowed in transform expressions");

			break;
		case EXPR_KIND_EXECUTE_PARAMETER:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in EXECUTE parameters");
			else
				fc_err = _("grouping operations are not allowed in EXECUTE parameters");

			break;
		case EXPR_KIND_TRIGGER_WHEN:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in trigger WHEN conditions");
			else
				fc_err = _("grouping operations are not allowed in trigger WHEN conditions");

			break;
		case EXPR_KIND_PARTITION_BOUND:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in partition bound");
			else
				fc_err = _("grouping operations are not allowed in partition bound");

			break;
		case EXPR_KIND_PARTITION_EXPRESSION:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in partition key expressions");
			else
				fc_err = _("grouping operations are not allowed in partition key expressions");

			break;
		case EXPR_KIND_GENERATED_COLUMN:

			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in column generation expressions");
			else
				fc_err = _("grouping operations are not allowed in column generation expressions");

			break;

		case EXPR_KIND_CALL_ARGUMENT:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in CALL arguments");
			else
				fc_err = _("grouping operations are not allowed in CALL arguments");

			break;

		case EXPR_KIND_COPY_WHERE:
			if (fc_isAgg)
				fc_err = _("aggregate functions are not allowed in COPY FROM WHERE conditions");
			else
				fc_err = _("grouping operations are not allowed in COPY FROM WHERE conditions");

			break;

		case EXPR_KIND_CYCLE_MARK:
			fc_errkind = true;
			break;

			/*
			 * 这里故意没有默认情况，以便编译器会警告如果我们添加一个新的 ParseExprKind 而没有扩展这个开关。如果我们在运行时看到一个未被识别的值，行为将与 EXPR_KIND_OTHER 相同，这在任何情况下都是合理的。
			 */
	}

	if (fc_err)
		ereport(ERROR,
				(errcode(ERRCODE_GROUPING_ERROR),
				 errmsg_internal("%s", fc_err),
				 parser_errposition(fc_pstate, fc_location)));

	if (fc_errkind)
	{
		if (fc_isAgg)
			/* 翻译者：%s 是 SQL 构造的名称，例如 GROUP BY */
			fc_err = _("aggregate functions are not allowed in %s");
		else
			/* 翻译者：%s 是 SQL 构造的名称，例如 GROUP BY */
			fc_err = _("grouping operations are not allowed in %s");

		ereport(ERROR,
				(errcode(ERRCODE_GROUPING_ERROR),
				 errmsg_internal(fc_err,
								 ParseExprKindName(fc_pstate->p_expr_kind)),
				 parser_errposition(fc_pstate, fc_location)));
	}
}

/*
 * check_agg_arguments
 *	  扫描聚合函数的参数以确定聚合的语义级别（零是当前选择的级别，一级是其父级，等等）。
 *
 * 聚合的级别与其聚合参数（包括任何 ORDER BY 列）或过滤表达式中的最低级变量或聚合的级别相同；或者如果它根本不包含任何变量，我们假定它是局部的。
 *
 * 直接参数中的 Vars/Aggs 不计入确定 agg 的级别，因为这些参数不是逐行计算的，而只是逐组计算，因此在某种意义上并不是真正的 agg 参数。然而，这可能意味着即使其直接参数包含较低级的 Vars/Aggs，我们也会决定一个 agg 是上层级别的，并且这种情况必须被禁止。（这有点奇怪，但 SQL 标准似乎相当明确，直接参数在设置 agg 的级别时不应被考虑。）
 *
 * 我们也借此机会检测参数中嵌套的任何聚合或窗口函数。如果我们找到窗口函数，可以立即抛出错误。聚合略微复杂，因为只有当内部聚合与外部的语义级别相同时才会出错，而我们在扫描参数完成之前无法知道这一点。
 */
static int fc_check_agg_arguments(ParseState *fc_pstate,
					List *fc_directargs,
					List *fc_args,
					Expr *fc_filter)
{
	int			fc_agglevel;
	check_agg_arguments_context fc_context;

	fc_context.pstate = fc_pstate;
	fc_context.min_varlevel = -1;	/* 表示尚未找到任何内容 */
	fc_context.min_agglevel = -1;
	fc_context.sublevels_up = 0;

	(void) fc_check_agg_arguments_walker((Node *) fc_args, &fc_context);
	(void) fc_check_agg_arguments_walker((Node *) fc_filter, &fc_context);

	/*
	 * 如果我们根本没有找到 vars 和 aggs，那就是一个级别零的聚合；
	 * 否则，其级别是 vars 或 aggs 的最小值。
	 */
	if (fc_context.min_varlevel < 0)
	{
		if (fc_context.min_agglevel < 0)
			fc_agglevel = 0;
		else
			fc_agglevel = fc_context.min_agglevel;
	}
	else if (fc_context.min_agglevel < 0)
		fc_agglevel = fc_context.min_varlevel;
	else
		fc_agglevel = Min(fc_context.min_varlevel, fc_context.min_agglevel);

	/*
	 * 如果有相同语义级别的嵌套聚合，报告错误。
	 */
	if (fc_agglevel == fc_context.min_agglevel)
	{
		int			fc_aggloc;

		fc_aggloc = locate_agg_of_level((Node *) fc_args, fc_agglevel);
		if (fc_aggloc < 0)
			fc_aggloc = locate_agg_of_level((Node *) fc_filter, fc_agglevel);
		ereport(ERROR,
				(errcode(ERRCODE_GROUPING_ERROR),
				 errmsg("aggregate function calls cannot be nested"),
				 parser_errposition(fc_pstate, fc_aggloc)));
	}

	/*
	 * 现在检查直接参数中的 vars/aggs，如果需要则抛出错误。请注意，我们允许具有 agg 的语义级别的 Var，但不允许该级别的 Agg。原则上这样的 Agg 可能被支持，但这会在执行时在聚合之间产生顺序依赖关系。由于这种情况似乎既不被规范要求，也不特别有用，因此我们只视其为嵌套聚合情况。
	 */
	if (fc_directargs)
	{
		fc_context.min_varlevel = -1;
		fc_context.min_agglevel = -1;
		(void) fc_check_agg_arguments_walker((Node *) fc_directargs, &fc_context);
		if (fc_context.min_varlevel >= 0 && fc_context.min_varlevel < fc_agglevel)
			ereport(ERROR,
					(errcode(ERRCODE_GROUPING_ERROR),
					 errmsg("outer-level aggregate cannot contain a lower-level variable in its direct arguments"),
					 parser_errposition(fc_pstate,
										locate_var_of_level((Node *) fc_directargs,
															fc_context.min_varlevel))));
		if (fc_context.min_agglevel >= 0 && fc_context.min_agglevel <= fc_agglevel)
			ereport(ERROR,
					(errcode(ERRCODE_GROUPING_ERROR),
					 errmsg("aggregate function calls cannot be nested"),
					 parser_errposition(fc_pstate,
										locate_agg_of_level((Node *) fc_directargs,
															fc_context.min_agglevel))));
	}
	return fc_agglevel;
}

static bool fc_check_agg_arguments_walker(Node *fc_node,
						   check_agg_arguments_context *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Var))
	{
		int			fc_varlevelsup = ((Var *) fc_node)->varlevelsup;

		/* 将 levelsup 转换为原始查询的参考框架 */
		fc_varlevelsup -= fc_context->sublevels_up;
		/* 忽略子查询的局部 vars */
		if (fc_varlevelsup >= 0)
		{
			if (fc_context->min_varlevel < 0 ||
				fc_context->min_varlevel > fc_varlevelsup)
				fc_context->min_varlevel = fc_varlevelsup;
		}
		return false;
	}
	if (IsA(fc_node, Aggref))
	{
		int			fc_agglevelsup = ((Aggref *) fc_node)->agglevelsup;

		/* 将 levelsup 转换为原始查询的参考框架 */
		fc_agglevelsup -= fc_context->sublevels_up;
		/* 忽略子查询的局部 aggs */
		if (fc_agglevelsup >= 0)
		{
			if (fc_context->min_agglevel < 0 ||
				fc_context->min_agglevel > fc_agglevelsup)
				fc_context->min_agglevel = fc_agglevelsup;
		}
		/* 继续并深入子树 */
	}
	if (IsA(fc_node, GroupingFunc))
	{
		int			fc_agglevelsup = ((GroupingFunc *) fc_node)->agglevelsup;

		/* 将 levelsup 转换为原始查询的参考框架 */
		fc_agglevelsup -= fc_context->sublevels_up;
		/* 忽略子查询的局部 aggs */
		if (fc_agglevelsup >= 0)
		{
			if (fc_context->min_agglevel < 0 ||
				fc_context->min_agglevel > fc_agglevelsup)
				fc_context->min_agglevel = fc_agglevelsup;
		}
		/* 继续并深入子树 */
	}

	/*
	 * SRFs 和窗口函数可以立即被拒绝，除非我们在聚合参数中的子选择中；在那种情况下，它们是可以的。
	 */
	if (fc_context->sublevels_up == 0)
	{
		if ((IsA(fc_node, FuncExpr) && ((FuncExpr *) fc_node)->funcretset) ||
			(IsA(fc_node, OpExpr) && ((OpExpr *) fc_node)->opretset))
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("aggregate function calls cannot contain set-returning function calls"),
					 errhint("You might be able to move the set-returning function into a LATERAL FROM item."),
					 parser_errposition(fc_context->pstate, exprLocation(fc_node))));
		if (IsA(fc_node, WindowFunc))
			ereport(ERROR,
					(errcode(ERRCODE_GROUPING_ERROR),
					 errmsg("aggregate function calls cannot contain window function calls"),
					 parser_errposition(fc_context->pstate,
										((WindowFunc *) fc_node)->location)));
	}
	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node,
								   fc_check_agg_arguments_walker,
								   (void *) fc_context,
								   0);
		fc_context->sublevels_up--;
		return fc_result;
	}

	return expression_tree_walker(fc_node,
								  fc_check_agg_arguments_walker,
								  (void *) fc_context);
}

/*
 * transformWindowFuncCall -
 *		完成窗口函数调用的初步转换
 *
 * parse_func.c 已将函数识别为窗口函数，并设置了 WindowFunc 的所有字段，除了 winref。在这里，我们必须（1）将 WindowDef 添加到 pstate（如果不是已经存在的重复项）并设置 winref 以链接到它；（2）在 pstate 中将 p_hasWindowFuncs 标记为 true。与聚合不同，仅需考虑最密切嵌套的 pstate 级别 —— SQL 规范没有“外部窗口函数”。
 */
void transformWindowFuncCall(ParseState *fc_pstate, WindowFunc *fc_wfunc,
						WindowDef *fc_windef)
{
	const char *fc_err;
	bool		fc_errkind;

	
/*
	 * 窗口函数调用不能包含另一个窗口函数（但聚合函数是可以的）。XXX
	 * 这是规范要求的，还是只是一个未实现的特性？
	 *
	 * 注意：我们不需要在这里检查过滤表达式，因为下面和在transformAggregateCall中的上下文检查
	 * 已经拒绝了过滤条件中的任何窗口函数或聚合函数。
	 */
	if (fc_pstate->p_hasWindowFuncs &&
		contain_windowfuncs((Node *) fc_wfunc->args))
		ereport(ERROR,
				(errcode(ERRCODE_WINDOWING_ERROR),
				 errmsg("window function calls cannot be nested"),
				 parser_errposition(fc_pstate,
									locate_windowfunc((Node *) fc_wfunc->args))));

	/*
	 * 检查窗口函数在查询中的位置是否不正确。
	 *
	 * 为了简洁，我们支持两种错误报告方案：将“err”设置为自定义消息，
	 * 或者如果错误上下文足够由ParseExprKindName返回的内容确定，则将“errkind”设置为true，*并且*
	 * 它所返回的仅仅是一个SQL关键字。（否则，使用自定义消息以避免产生翻译问题。）
	 */
	fc_err = NULL;
	fc_errkind = false;
	switch (fc_pstate->p_expr_kind)
	{
		case EXPR_KIND_NONE:
			Assert(false);		/* 不能发生 */
			break;
		case EXPR_KIND_OTHER:
			/* 在这里接受窗口函数；调用者如果需要必须抛出错误 */
			break;
		case EXPR_KIND_JOIN_ON:
		case EXPR_KIND_JOIN_USING:
			fc_err = _("window functions are not allowed in JOIN conditions");
			break;
		case EXPR_KIND_FROM_SUBSELECT:
			/* 不能到这里，但以防万一，抛出错误 */
			fc_errkind = true;
			break;
		case EXPR_KIND_FROM_FUNCTION:
			fc_err = _("window functions are not allowed in functions in FROM");
			break;
		case EXPR_KIND_WHERE:
			fc_errkind = true;
			break;
		case EXPR_KIND_POLICY:
			fc_err = _("window functions are not allowed in policy expressions");
			break;
		case EXPR_KIND_HAVING:
			fc_errkind = true;
			break;
		case EXPR_KIND_FILTER:
			fc_errkind = true;
			break;
		case EXPR_KIND_WINDOW_PARTITION:
		case EXPR_KIND_WINDOW_ORDER:
		case EXPR_KIND_WINDOW_FRAME_RANGE:
		case EXPR_KIND_WINDOW_FRAME_ROWS:
		case EXPR_KIND_WINDOW_FRAME_GROUPS:
			fc_err = _("window functions are not allowed in window definitions");
			break;
		case EXPR_KIND_SELECT_TARGET:
			/* 可以 */
			break;
		case EXPR_KIND_INSERT_TARGET:
		case EXPR_KIND_UPDATE_SOURCE:
		case EXPR_KIND_UPDATE_TARGET:
			fc_errkind = true;
			break;
		case EXPR_KIND_MERGE_WHEN:
			fc_err = _("window functions are not allowed in MERGE WHEN conditions");
			break;
		case EXPR_KIND_GROUP_BY:
			fc_errkind = true;
			break;
		case EXPR_KIND_ORDER_BY:
			/* 可以 */
			break;
		case EXPR_KIND_DISTINCT_ON:
			/* 可以 */
			break;
		case EXPR_KIND_LIMIT:
		case EXPR_KIND_OFFSET:
			fc_errkind = true;
			break;
		case EXPR_KIND_RETURNING:
			fc_errkind = true;
			break;
		case EXPR_KIND_VALUES:
		case EXPR_KIND_VALUES_SINGLE:
			fc_errkind = true;
			break;
		case EXPR_KIND_CHECK_CONSTRAINT:
		case EXPR_KIND_DOMAIN_CHECK:
			fc_err = _("window functions are not allowed in check constraints");
			break;
		case EXPR_KIND_COLUMN_DEFAULT:
		case EXPR_KIND_FUNCTION_DEFAULT:
			fc_err = _("window functions are not allowed in DEFAULT expressions");
			break;
		case EXPR_KIND_INDEX_EXPRESSION:
			fc_err = _("window functions are not allowed in index expressions");
			break;
		case EXPR_KIND_STATS_EXPRESSION:
			fc_err = _("window functions are not allowed in statistics expressions");
			break;
		case EXPR_KIND_INDEX_PREDICATE:
			fc_err = _("window functions are not allowed in index predicates");
			break;
		case EXPR_KIND_ALTER_COL_TRANSFORM:
			fc_err = _("window functions are not allowed in transform expressions");
			break;
		case EXPR_KIND_EXECUTE_PARAMETER:
			fc_err = _("window functions are not allowed in EXECUTE parameters");
			break;
		case EXPR_KIND_TRIGGER_WHEN:
			fc_err = _("window functions are not allowed in trigger WHEN conditions");
			break;
		case EXPR_KIND_PARTITION_BOUND:
			fc_err = _("window functions are not allowed in partition bound");
			break;
		case EXPR_KIND_PARTITION_EXPRESSION:
			fc_err = _("window functions are not allowed in partition key expressions");
			break;
		case EXPR_KIND_CALL_ARGUMENT:
			fc_err = _("window functions are not allowed in CALL arguments");
			break;
		case EXPR_KIND_COPY_WHERE:
			fc_err = _("window functions are not allowed in COPY FROM WHERE conditions");
			break;
		case EXPR_KIND_GENERATED_COLUMN:
			fc_err = _("window functions are not allowed in column generation expressions");
			break;
		case EXPR_KIND_CYCLE_MARK:
			fc_errkind = true;
			break;

			/*
			 * 这里故意没有默认情况，以便编译器会警告如果我们添加一个新的 ParseExprKind 而没有扩展这个开关。如果我们在运行时看到一个未被识别的值，行为将与 EXPR_KIND_OTHER 相同，这在任何情况下都是合理的。
			 */
	}
	if (fc_err)
		ereport(ERROR,
				(errcode(ERRCODE_WINDOWING_ERROR),
				 errmsg_internal("%s", fc_err),
				 parser_errposition(fc_pstate, fc_wfunc->location)));
	if (fc_errkind)
		ereport(ERROR,
				(errcode(ERRCODE_WINDOWING_ERROR),
		/* 翻译者：%s 是 SQL 构造的名称，例如 GROUP BY */
				 errmsg("window functions are not allowed in %s",
						ParseExprKindName(fc_pstate->p_expr_kind)),
				 parser_errposition(fc_pstate, fc_wfunc->location)));

	/*
	 * 如果OVER子句只指定了一个窗口名称，则找到该WINDOW
	 * 子句（最好是存在的）。否则，尝试匹配OVER子句的所有属性，
	 * 如果没有成功，则在p_windowdefs列表中创建一个新的条目。
	 */
	if (fc_windef->name)
	{
		Index		fc_winref = 0;
		ListCell   *fc_lc;

		Assert(fc_windef->refname == NULL &&
			   fc_windef->partitionClause == NIL &&
			   fc_windef->orderClause == NIL &&
			   fc_windef->frameOptions == FRAMEOPTION_DEFAULTS);

		foreach(fc_lc, fc_pstate->p_windowdefs)
		{
			WindowDef  *fc_refwin = (WindowDef *) lfirst(fc_lc);

			fc_winref++;
			if (fc_refwin->name && strcmp(fc_refwin->name, fc_windef->name) == 0)
			{
				fc_wfunc->winref = fc_winref;
				break;
			}
		}
		if (fc_lc == NULL)			/* 没找到？ */
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_OBJECT),
					 errmsg("window \"%s\" does not exist", fc_windef->name),
					 parser_errposition(fc_pstate, fc_windef->location)));
	}
	else
	{
		Index		fc_winref = 0;
		ListCell   *fc_lc;

		foreach(fc_lc, fc_pstate->p_windowdefs)
		{
			WindowDef  *fc_refwin = (WindowDef *) lfirst(fc_lc);

			fc_winref++;
			if (fc_refwin->refname && fc_windef->refname &&
				strcmp(fc_refwin->refname, fc_windef->refname) == 0)
				 /* 根据引用名称匹配 */ ;
			else if (!fc_refwin->refname && !fc_windef->refname)
				 /* 匹配，但没有引用名称 */ ;
			else
				continue;
			if (equal(fc_refwin->partitionClause, fc_windef->partitionClause) &&
				equal(fc_refwin->orderClause, fc_windef->orderClause) &&
				fc_refwin->frameOptions == fc_windef->frameOptions &&
				equal(fc_refwin->startOffset, fc_windef->startOffset) &&
				equal(fc_refwin->endOffset, fc_windef->endOffset))
			{
				/* 找到重复的窗口规范 */
				fc_wfunc->winref = fc_winref;
				break;
			}
		}
		if (fc_lc == NULL)			/* 没找到？ */
		{
			fc_pstate->p_windowdefs = lappend(fc_pstate->p_windowdefs, fc_windef);
			fc_wfunc->winref = list_length(fc_pstate->p_windowdefs);
		}
	}

	fc_pstate->p_hasWindowFuncs = true;
}

/*
 * parseCheckAggregates
 *	检查聚合函数是否处于不该出现的地方以及分组是否不当。
 *	此函数应在目标列表和资格确定后调用。
 *
 *	错误位置的聚合函数现在主要在transformAggregateCall中检测，
 *	但在所有内容最终确定后再检查递归查询中的聚合函数似乎更加稳健。
 *	在任何情况下，实时检测不当分组非常困难，因此我们必须
 *	对查询进行另一次遍历来处理这个问题。
 */
void parseCheckAggregates(ParseState *fc_pstate, Query *fc_qry)
{
	List	   *fc_gset_common = NIL;
	List	   *fc_groupClauses = NIL;
	List	   *fc_groupClauseCommonVars = NIL;
	bool		fc_have_non_var_grouping;
	List	   *fc_func_grouped_rels = NIL;
	ListCell   *fc_l;
	bool		fc_hasJoinRTEs;
	bool		fc_hasSelfRefRTEs;
	Node	   *fc_clause;

	/* 仅在发现聚合或分组时调用 */
	Assert(fc_pstate->p_hasAggs || fc_qry->groupClause || fc_qry->havingQual || fc_qry->groupingSets);

	/*
	 * 如果我们有分组集，则展开它们并找到所有
	 * 集合的交集。
	 */
	if (fc_qry->groupingSets)
	{
		/*
		 * 4096的限制是任意的，存在的目的是为了避免
		 * 病态构造造成资源问题。
		 */
		List	   *fc_gsets = expand_grouping_sets(fc_qry->groupingSets, fc_qry->groupDistinct, 4096);

		if (!fc_gsets)
			ereport(ERROR,
					(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
					 errmsg("too many grouping sets present (maximum 4096)"),
					 parser_errposition(fc_pstate,
										fc_qry->groupClause
										? exprLocation((Node *) fc_qry->groupClause)
										: exprLocation((Node *) fc_qry->groupingSets))));

		/*
		 * 交集通常是空的，所以通过用最小的集合
		 * 来引导交集。
		 */
		fc_gset_common = linitial(fc_gsets);

		if (fc_gset_common)
		{
			for_each_from(fc_l, fc_gsets, 1)
			{
				fc_gset_common = list_intersection_int(fc_gset_common, lfirst(fc_l));
				if (!fc_gset_common)
					break;
			}
		}

		/*
		 * 如果在扩展中只有一个分组集，并且
		 * groupClause 非空（意味着分组集也不是
		 * 空的），那么我们可以抛弃分组集，假装
		 * 我们只是进行了正常的 GROUP BY。
		 */
		if (list_length(fc_gsets) == 1 && fc_qry->groupClause)
			fc_qry->groupingSets = NIL;
	}

	/*
	 * 扫描范围表以查看是否存在 JOIN 或自引用 CTE
	 * 条目。我们将在下面需要这个信息。
	 */
	fc_hasJoinRTEs = fc_hasSelfRefRTEs = false;
	foreach(fc_l, fc_pstate->p_rtable)
	{
		RangeTblEntry *fc_rte = (RangeTblEntry *) lfirst(fc_l);

		if (fc_rte->rtekind == RTE_JOIN)
			fc_hasJoinRTEs = true;
		else if (fc_rte->rtekind == RTE_CTE && fc_rte->self_reference)
			fc_hasSelfRefRTEs = true;
	}

	/*
	 * 构建可接受的 GROUP BY 表达式列表，以供
	 * check_ungrouped_columns() 使用。
	 *
	 * 我们获取 TLE，而不仅仅是 expr，因为 GROUPING 需要知道
	 * sortgroupref。
	 */
	foreach(fc_l, fc_qry->groupClause)
	{
		SortGroupClause *fc_grpcl = (SortGroupClause *) lfirst(fc_l);
		TargetEntry *fc_expr;

		fc_expr = get_sortgroupclause_tle(fc_grpcl, fc_qry->targetList);
		if (fc_expr == NULL)
			continue;			/* 大概不会发生 */

		fc_groupClauses = lappend(fc_groupClauses, fc_expr);
	}

	/*
	 * 如果涉及连接别名变量，我们必须将它们展平到
	 * 基础变量，以便别名变量和非别名变量能够被
	 * 正确地视为相等。如果没有范围表
	 * 条目是 RTE_JOIN 类型，我们可以跳过
	 * 这样做的开销。
	 */
	if (fc_hasJoinRTEs)
		fc_groupClauses = (List *) flatten_join_alias_vars(fc_qry,
														(Node *) fc_groupClauses);

	/*
	 * 检测是否有任何分组表达式不是简单的 Vars；如果
	 * 它们都是 Vars，那么我们在递归
	 * 扫描中就不必那么费劲。（请注意，我们必须在此之前
	 * 展平别名。）
	 *
	 * 将包含在所有分组集中的 Vars 单独跟踪
	 * 在 groupClauseCommonVars 中，因为这些是我们可以用
	 * 来检查函数依赖性的唯一变量。
	 */
	fc_have_non_var_grouping = false;
	foreach(fc_l, fc_groupClauses)
	{
		TargetEntry *fc_tle = lfirst(fc_l);

		if (!IsA(fc_tle->expr, Var))
		{
			fc_have_non_var_grouping = true;
		}
		else if (!fc_qry->groupingSets ||
				 list_member_int(fc_gset_common, fc_tle->ressortgroupref))
		{
			fc_groupClauseCommonVars = lappend(fc_groupClauseCommonVars, fc_tle->expr);
		}
	}

	/*
	 * 检查目标列表和 HAVING 子句中的未分组变量。
	 *
	 * 注意：因为我们检查 resjunk tlist 元素和常规元素，
	 * 所以这也会找到来自 ORDER BY 和
	 * WINDOW 子句的未分组变量。就这一点而言，
	 * 它也会检查分组表达式本身——但它们都会通过测试 ...
	 *
	 * 我们还会最终确定 GROUPING 表达式，但为此我们需要遍历
	 * 原始（未展平）子句以修改节点。
	 */
	fc_clause = (Node *) fc_qry->targetList;
	fc_finalize_grouping_exprs(fc_clause, fc_pstate, fc_qry,
							fc_groupClauses, fc_hasJoinRTEs,
							fc_have_non_var_grouping);
	if (fc_hasJoinRTEs)
		fc_clause = flatten_join_alias_vars(fc_qry, fc_clause);
	fc_check_ungrouped_columns(fc_clause, fc_pstate, fc_qry,
							fc_groupClauses, fc_groupClauseCommonVars,
							fc_have_non_var_grouping,
							&fc_func_grouped_rels);

	fc_clause = (Node *) fc_qry->havingQual;
	fc_finalize_grouping_exprs(fc_clause, fc_pstate, fc_qry,
							fc_groupClauses, fc_hasJoinRTEs,
							fc_have_non_var_grouping);
	if (fc_hasJoinRTEs)
		fc_clause = flatten_join_alias_vars(fc_qry, fc_clause);
	fc_check_ungrouped_columns(fc_clause, fc_pstate, fc_qry,
							fc_groupClauses, fc_groupClauseCommonVars,
							fc_have_non_var_grouping,
							&fc_func_grouped_rels);

	/*
	 * 根据规范，聚合不能出现在递归项中。
	 */
	if (fc_pstate->p_hasAggs && fc_hasSelfRefRTEs)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_RECURSION),
				 errmsg("aggregate functions are not allowed in a recursive query's recursive term"),
				 parser_errposition(fc_pstate,
									locate_agg_of_level((Node *) fc_qry, 0))));
}

/*
 * check_ungrouped_columns -
 *	  扫描给定的表达式树以查找未分组变量（这些变量
 *	  不在 groupClauses 列表中，并且不在聚合函数的
 *	  参数内）。如果找到任何变量，则发出适当的错误消息。
 *
 * 注意：我们假设给定的子句已被适当地转化为
 * 解析器输出。这意味着我们可以使用 expression_tree_walker。
 *
 * 注意：我们在主查询中识别分组表达式，但只在子查询中
 * 识别分组 Vars。例如，这将被拒绝，
 * 尽管它可能被允许：
 *		SELECT
 *			(SELECT x FROM bar where y = (foo.a + foo.b))
 *		FROM foo
 *		GROUP BY a + b;
 * 问题在于需要考虑不同的 sublevels_up。
 * 这显然需要一个完全自定义的 equal() 版本，
 * 这比这个功能看起来更麻烦。
 */
static void fc_check_ungrouped_columns(Node *fc_node, ParseState *fc_pstate, Query *fc_qry,
						List *fc_groupClauses, List *fc_groupClauseCommonVars,
						bool fc_have_non_var_grouping,
						List **fc_func_grouped_rels)
{
	check_ungrouped_columns_context fc_context;

	fc_context.pstate = fc_pstate;
	fc_context.qry = fc_qry;
	fc_context.hasJoinRTEs = false;	/* 假设调用者展平了连接 Vars */
	fc_context.groupClauses = fc_groupClauses;
	fc_context.groupClauseCommonVars = fc_groupClauseCommonVars;
	fc_context.have_non_var_grouping = fc_have_non_var_grouping;
	fc_context.func_grouped_rels = fc_func_grouped_rels;
	fc_context.sublevels_up = 0;
	fc_context.in_agg_direct_args = false;
	fc_check_ungrouped_columns_walker(fc_node, &fc_context);
}

static bool fc_check_ungrouped_columns_walker(Node *fc_node,
							   check_ungrouped_columns_context *fc_context)
{
	ListCell   *fc_gl;

	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Const) ||
		IsA(fc_node, Param))
		return false;			/* 常量总是可接受的 */

	if (IsA(fc_node, Aggref))
	{
		Aggref	   *fc_agg = (Aggref *) fc_node;

		if ((int) fc_agg->agglevelsup == fc_context->sublevels_up)
		{
			/*
			 * 如果我们发现原始级别的聚合调用，不要
			 * 递归到其正常参数、ORDER BY 参数或
			 * 过滤器中；未分组变量在那里不是错误。
			 * 但是我们应该像处理直接参数一样检查
			 * 直接参数，因为它们不在聚合中。
			 * 我们在上下文中设置一个特殊标志，以帮助生成一个有用的
			 * 错误消息，用于直接参数中的未分组变量。
			 */
			bool		fc_result;

			Assert(!fc_context->in_agg_direct_args);
			fc_context->in_agg_direct_args = true;
			fc_result = fc_check_ungrouped_columns_walker((Node *) fc_agg->aggdirectargs,
													fc_context);
			fc_context->in_agg_direct_args = false;
			return fc_result;
		}

		/*
		 * 我们可以完全跳过更高层级的聚合递归，
		 * 因为它们不可能包含我们关心的 Vars（见
		 * transformAggregateCall）。不过，我们确实需要查看
		 * 低层级的聚合。
		 */
		if ((int) fc_agg->agglevelsup > fc_context->sublevels_up)
			return false;
	}

	if (IsA(fc_node, GroupingFunc))
	{
		GroupingFunc *fc_grp = (GroupingFunc *) fc_node;

		/* 单独处理 GroupingFunc，无需在此级别重检 */

		if ((int) fc_grp->agglevelsup >= fc_context->sublevels_up)
			return false;
	}

	/*
	 * 如果我们有任何不是简单 Vars 的 GROUP BY 项，检查子表达式
	 * 整体是否与任何 GROUP BY 项匹配。我们需要在每个递归
	 * 级别执行此操作，以便在到达其中的变量之前识别 GROUPed-BY 表达式。
	 * 但这仅在外部查询级别有效，如上所述。
	 */
	if (fc_context->have_non_var_grouping && fc_context->sublevels_up == 0)
	{
		foreach(fc_gl, fc_context->groupClauses)
		{
			TargetEntry *fc_tle = lfirst(fc_gl);

			if (equal(fc_node, fc_tle->expr))
				return false;	/* 可接受，不再深入 */
		}
	}

	/*
	 * 如果我们在原始查询级别有未分组的 Var，则我们失败。
	 * 原始查询级别以下的 Vars 不是问题，以上的 Vars 也不是。
	 * （如果这些 Vars 在其自己的查询级别上是未分组的，那是
	 * 别人的问题...）
	 */
	if (IsA(fc_node, Var))
	{
		Var		   *fc_var = (Var *) fc_node;
		RangeTblEntry *fc_rte;
		char	   *fc_attname;

		if (fc_var->varlevelsup != fc_context->sublevels_up)
			return false;		/* 它不是我查询的本地变量，忽略 */

		/*
		 * 检查匹配项，如果我们不在上面完成。
		 */
		if (!fc_context->have_non_var_grouping || fc_context->sublevels_up != 0)
		{
			foreach(fc_gl, fc_context->groupClauses)
			{
				Var		   *fc_gvar = (Var *) ((TargetEntry *) lfirst(fc_gl))->expr;

				if (IsA(fc_gvar, Var) &&
					fc_gvar->varno == fc_var->varno &&
					fc_gvar->varattno == fc_var->varattno &&
					fc_gvar->varlevelsup == 0)
					return false;	/* 可接受，我们没问题 */
			}
		}

		
/*
		 * 检查变量是否在功能上依赖于 GROUP BY 列。如果是，我们可以允许使用该变量，因为对于这个表而言，分组实际上没有作用。然而，这种推断依赖于表的一个或多个约束，因此我们必须将这些约束添加到查询的 constraintDeps 列表中，因为如果约束被丢弃，那么这在语义上就不再有效。
		 * （因此，这个检查必须是最后的努力，才能提出错误：我们不想不必要地添加依赖关系。）
		 *
		 * 因为这是一个相当昂贵的检查，并且对于表的所有列会有相同的结果，我们记住了哪些 RTE 已经证明了功能依赖关系，存储在 func_grouped_rels 列表中。这个测试还防止我们向 constraintDeps 列表添加重复条目。
		 */
		if (list_member_int(*fc_context->func_grouped_rels, fc_var->varno))
			return false;		/* 之前已证明可接受 */

		Assert(fc_var->varno > 0 &&
			   (int) fc_var->varno <= list_length(fc_context->pstate->p_rtable));
		fc_rte = rt_fetch(fc_var->varno, fc_context->pstate->p_rtable);
		if (fc_rte->rtekind == RTE_RELATION)
		{
			if (check_functional_grouping(fc_rte->relid,
										  fc_var->varno,
										  0,
										  fc_context->groupClauseCommonVars,
										  &fc_context->qry->constraintDeps))
			{
				*fc_context->func_grouped_rels =
					lappend_int(*fc_context->func_grouped_rels, fc_var->varno);
				return false;	/* 可接受 */
			}
		}

		/* 发现一个未分组的局部变量；生成错误信息 */
		fc_attname = get_rte_attribute_name(fc_rte, fc_var->varattno);
		if (fc_context->sublevels_up == 0)
			ereport(ERROR,
					(errcode(ERRCODE_GROUPING_ERROR),
					 errmsg("column \"%s.%s\" must appear in the GROUP BY clause or be used in an aggregate function",
							fc_rte->eref->aliasname, fc_attname),
					 fc_context->in_agg_direct_args ?
					 errdetail("Direct arguments of an ordered-set aggregate must use only grouped columns.") : 0,
					 parser_errposition(fc_context->pstate, fc_var->location)));
		else
			ereport(ERROR,
					(errcode(ERRCODE_GROUPING_ERROR),
					 errmsg("subquery uses ungrouped column \"%s.%s\" from outer query",
							fc_rte->eref->aliasname, fc_attname),
					 parser_errposition(fc_context->pstate, fc_var->location)));
	}

	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node,
								   fc_check_ungrouped_columns_walker,
								   (void *) fc_context,
								   0);
		fc_context->sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_check_ungrouped_columns_walker,
								  (void *) fc_context);
}

/*
 * finalize_grouping_exprs -
 *	  扫描给定的表达式树以查找 GROUPING() 和相关调用，
 *	  并验证和处理它们的参数。
 *
 * 这部分从上面的 check_ungrouped_columns 中分离出来，因为它需要
 * 修改节点（是就地修改，而不是通过变异器）而 check_ungrouped_columns 可能仅看到原始的副本，得益于
 * 连接别名变量的扁平化。因此，在比较之前，我们在看到它时，对每个单独的 GROUPING 参数进行扁平化。
 */
static void fc_finalize_grouping_exprs(Node *fc_node, ParseState *fc_pstate, Query *fc_qry,
						List *fc_groupClauses, bool fc_hasJoinRTEs,
						bool fc_have_non_var_grouping)
{
	check_ungrouped_columns_context fc_context;

	fc_context.pstate = fc_pstate;
	fc_context.qry = fc_qry;
	fc_context.hasJoinRTEs = fc_hasJoinRTEs;
	fc_context.groupClauses = fc_groupClauses;
	fc_context.groupClauseCommonVars = NIL;
	fc_context.have_non_var_grouping = fc_have_non_var_grouping;
	fc_context.func_grouped_rels = NULL;
	fc_context.sublevels_up = 0;
	fc_context.in_agg_direct_args = false;
	fc_finalize_grouping_exprs_walker(fc_node, &fc_context);
}

static bool fc_finalize_grouping_exprs_walker(Node *fc_node,
							   check_ungrouped_columns_context *fc_context)
{
	ListCell   *fc_gl;

	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, Const) ||
		IsA(fc_node, Param))
		return false;			/* 常量总是可接受的 */

	if (IsA(fc_node, Aggref))
	{
		Aggref	   *fc_agg = (Aggref *) fc_node;

		if ((int) fc_agg->agglevelsup == fc_context->sublevels_up)
		{
			/*
			 * 如果我们发现原始级别的聚合调用，不要递归地进入它的正常参数、ORDER BY 参数或
			 * 筛选；此级别的 GROUPING 表达式在那里是不允许的。但是检查直接参数，就好像它们不在聚合中。
			 */
			bool		fc_result;

			Assert(!fc_context->in_agg_direct_args);
			fc_context->in_agg_direct_args = true;
			fc_result = fc_finalize_grouping_exprs_walker((Node *) fc_agg->aggdirectargs,
													fc_context);
			fc_context->in_agg_direct_args = false;
			return fc_result;
		}

		/*
		 * 我们可以完全跳过对更高级别聚合的递归，因为它们不可能包含对我们关心的表达式（见
		 * transformAggregateCall）。但是，我们确实需要查看低级别的聚合。
		 */
		if ((int) fc_agg->agglevelsup > fc_context->sublevels_up)
			return false;
	}

	if (IsA(fc_node, GroupingFunc))
	{
		GroupingFunc *fc_grp = (GroupingFunc *) fc_node;

		/*
		 * 我们只需要检查与其所属级别完全相同的 GroupingFunc 节点，因为它们的参数不能混合级别。
		 */

		if ((int) fc_grp->agglevelsup == fc_context->sublevels_up)
		{
			ListCell   *fc_lc;
			List	   *fc_ref_list = NIL;

			foreach(fc_lc, fc_grp->args)
			{
				Node	   *fc_expr = lfirst(fc_lc);
				Index		fc_ref = 0;

				if (fc_context->hasJoinRTEs)
					fc_expr = flatten_join_alias_vars(fc_context->qry, fc_expr);

				/*
				 * 每个表达式必须与当前查询级别的分组条目匹配。与一般表达式情况不同，我们不允许
				 * 功能依赖或外部引用。
				 */

				if (IsA(fc_expr, Var))
				{
					Var		   *fc_var = (Var *) fc_expr;

					if (fc_var->varlevelsup == fc_context->sublevels_up)
					{
						foreach(fc_gl, fc_context->groupClauses)
						{
							TargetEntry *fc_tle = lfirst(fc_gl);
							Var		   *fc_gvar = (Var *) fc_tle->expr;

							if (IsA(fc_gvar, Var) &&
								fc_gvar->varno == fc_var->varno &&
								fc_gvar->varattno == fc_var->varattno &&
								fc_gvar->varlevelsup == 0)
							{
								fc_ref = fc_tle->ressortgroupref;
								break;
							}
						}
					}
				}
				else if (fc_context->have_non_var_grouping &&
						 fc_context->sublevels_up == 0)
				{
					foreach(fc_gl, fc_context->groupClauses)
					{
						TargetEntry *fc_tle = lfirst(fc_gl);

						if (equal(fc_expr, fc_tle->expr))
						{
							fc_ref = fc_tle->ressortgroupref;
							break;
						}
					}
				}

				if (fc_ref == 0)
					ereport(ERROR,
							(errcode(ERRCODE_GROUPING_ERROR),
							 errmsg("arguments to GROUPING must be grouping expressions of the associated query level"),
							 parser_errposition(fc_context->pstate,
												exprLocation(fc_expr))));

				fc_ref_list = lappend_int(fc_ref_list, fc_ref);
			}

			fc_grp->refs = fc_ref_list;
		}

		if ((int) fc_grp->agglevelsup > fc_context->sublevels_up)
			return false;
	}

	if (IsA(fc_node, Query))
	{
		/* 递归进入子选择 */
		bool		fc_result;

		fc_context->sublevels_up++;
		fc_result = query_tree_walker((Query *) fc_node,
								   fc_finalize_grouping_exprs_walker,
								   (void *) fc_context,
								   0);
		fc_context->sublevels_up--;
		return fc_result;
	}
	return expression_tree_walker(fc_node, fc_finalize_grouping_exprs_walker,
								  (void *) fc_context);
}


/*
 * 给定一个 GroupingSet 节点，扩展它并返回一个列表的列表。
 *
 * 对于 EMPTY 节点，返回一个包含一个空列表的列表。
 *
 * 对于 SIMPLE 节点，返回一个包含一个列表的列表，该列表即为节点内容。
 *
 * 对于 CUBE 和 ROLLUP 节点，返回扩展的列表。
 *
 * 对于 SET 节点，递归扩展包含的 CUBE 和 ROLLUP。
 */
static List * fc_expand_groupingset_node(GroupingSet *fc_gs)
{
	List	   *fc_result = NIL;

	switch (fc_gs->kind)
	{
		case GROUPING_SET_EMPTY:
			fc_result = list_make1(NIL);
			break;

		case GROUPING_SET_SIMPLE:
			fc_result = list_make1(fc_gs->content);
			break;

		case GROUPING_SET_ROLLUP:
			{
				List	   *fc_rollup_val = fc_gs->content;
				ListCell   *fc_lc;
				int			fc_curgroup_size = list_length(fc_gs->content);

				while (fc_curgroup_size > 0)
				{
					List	   *fc_current_result = NIL;
					int			fc_i = fc_curgroup_size;

					foreach(fc_lc, fc_rollup_val)
					{
						GroupingSet *fc_gs_current = (GroupingSet *) lfirst(fc_lc);

						Assert(fc_gs_current->kind == GROUPING_SET_SIMPLE);

						fc_current_result = list_concat(fc_current_result,
													 fc_gs_current->content);

						/* 如果我们完成了当前组的构建，退出 */
						if (--fc_i == 0)
							break;
					}

					fc_result = lappend(fc_result, fc_current_result);
					--fc_curgroup_size;
				}

				fc_result = lappend(fc_result, NIL);
			}
			break;

		case GROUPING_SET_CUBE:
			{
				List	   *fc_cube_list = fc_gs->content;
				int			fc_number_bits = list_length(fc_cube_list);
				uint32		fc_num_sets;
				uint32		fc_i;

				/* 解析器应该将这个限制得更低 */
				Assert(fc_number_bits < 31);

				fc_num_sets = (1U << fc_number_bits);

				for (fc_i = 0; fc_i < fc_num_sets; fc_i++)
				{
					List	   *fc_current_result = NIL;
					ListCell   *fc_lc;
					uint32		fc_mask = 1U;

					foreach(fc_lc, fc_cube_list)
					{
						GroupingSet *fc_gs_current = (GroupingSet *) lfirst(fc_lc);

						Assert(fc_gs_current->kind == GROUPING_SET_SIMPLE);

						if (fc_mask & fc_i)
							fc_current_result = list_concat(fc_current_result,
														 fc_gs_current->content);

						fc_mask <<= 1;
					}

					fc_result = lappend(fc_result, fc_current_result);
				}
			}
			break;

		case GROUPING_SET_SETS:
			{
				ListCell   *fc_lc;

				foreach(fc_lc, fc_gs->content)
				{
					List	   *fc_current_result = fc_expand_groupingset_node(lfirst(fc_lc));

					fc_result = list_concat(fc_result, fc_current_result);
				}
			}
			break;
	}

	return fc_result;
}

/* list_sort 比较器按长度对子列表进行排序 */
static int fc_cmp_list_len_asc(const ListCell *fc_a, const ListCell *fc_b)
{
	int			fc_la = list_length((const List *) lfirst(fc_a));
	int			fc_lb = list_length((const List *) lfirst(fc_b));

	return (fc_la > fc_lb) ? 1 : (fc_la == fc_lb) ? 0 : -1;
}

/* list_sort 比较器按长度和内容对子列表进行排序 */
static int fc_cmp_list_len_contents_asc(const ListCell *fc_a, const ListCell *fc_b)
{
	int			fc_res = fc_cmp_list_len_asc(fc_a, fc_b);

	if (fc_res == 0)
	{
		List	   *fc_la = (List *) lfirst(fc_a);
		List	   *fc_lb = (List *) lfirst(fc_b);
		ListCell   *fc_lca;
		ListCell   *fc_lcb;

		forboth(fc_lca, fc_la, fc_lcb, fc_lb)
		{
			int			fc_va = lfirst_int(fc_lca);
			int			fc_vb = lfirst_int(fc_lcb);

			if (fc_va > fc_vb)
				return 1;
			if (fc_va < fc_vb)
				return -1;
		}
	}

	return fc_res;
}

/*
 * 扩展 groupingSets 子句为扁平的分组集列表。
 * 返回的列表按长度排序，最短的集合在前。
 *
 * 这主要是为了规划器，但我们在这里也使用它来进行一些一致性检查。
 */
List * expand_grouping_sets(List *fc_groupingSets, bool fc_groupDistinct, int fc_limit)
{
	List	   *fc_expanded_groups = NIL;
	List	   *fc_result = NIL;
	double		fc_numsets = 1;
	ListCell   *fc_lc;

	if (fc_groupingSets == NIL)
		return NIL;

	foreach(fc_lc, fc_groupingSets)
	{
		List	   *fc_current_result = NIL;
		GroupingSet *fc_gs = lfirst(fc_lc);

		fc_current_result = fc_expand_groupingset_node(fc_gs);

		Assert(fc_current_result != NIL);

		fc_numsets *= list_length(fc_current_result);

		if (fc_limit >= 0 && fc_numsets > fc_limit)
			return NIL;

		fc_expanded_groups = lappend(fc_expanded_groups, fc_current_result);
	}

	/*
	 * 在 expanded_groups 的子列表之间进行笛卡尔积。同时，
	 * 从各个分组集移除任何重复元素（但我们必须
	 * 不改变集合的数量）
	 */

	foreach(fc_lc, (List *) linitial(fc_expanded_groups))
	{
		fc_result = lappend(fc_result, list_union_int(NIL, (List *) lfirst(fc_lc)));
	}

	for_each_from(fc_lc, fc_expanded_groups, 1)
	{
		List	   *fc_p = lfirst(fc_lc);
		List	   *fc_new_result = NIL;
		ListCell   *fc_lc2;

		foreach(fc_lc2, fc_result)
		{
			List	   *fc_q = lfirst(fc_lc2);
			ListCell   *fc_lc3;

			foreach(fc_lc3, fc_p)
			{
				fc_new_result = lappend(fc_new_result,
									 list_union_int(fc_q, (List *) lfirst(fc_lc3)));
			}
		}
		fc_result = fc_new_result;
	}

	/* 现在按长度排序列表，并在必要时去重 */
	if (!fc_groupDistinct || list_length(fc_result) < 2)
		list_sort(fc_result, fc_cmp_list_len_asc);
	else
	{
		ListCell   *fc_cell;
		List	   *fc_prev;

		/* 单独对每个 groupset 进行排序 */
		foreach(fc_cell, fc_result)
			list_sort(lfirst(fc_cell), list_int_cmp);

		/* 现在按长度和内容对 groupsets 列表进行排序 */
		list_sort(fc_result, fc_cmp_list_len_contents_asc);

		/* 最后，移除重复项 */
		fc_prev = linitial(fc_result);
		for_each_from(fc_cell, fc_result, 1)
		{
			if (equal(lfirst(fc_cell), fc_prev))
				fc_result = foreach_delete_current(fc_result, fc_cell);
			else
				fc_prev = lfirst(fc_cell);
		}
	}

	return fc_result;
}

/*
 * get_aggregate_argtypes
 *	识别传递给聚合调用的特定数据类型。
 *
 * 给定一个 Aggref，提取输入参数的实际数据类型。
 * 输入数据类型以与聚合声明相匹配的方式报告，即，任何附加到普通
 * 聚合的 ORDER BY 列都被忽略，但我们报告有序集聚合的直接和聚合参数。
 *
 * 数据类型被返回到 inputTypes[] 中，该数组的长度必须为 FUNC_MAX_ARGS。
 *
 * 函数结果是实际参数的数量。
 */
int get_aggregate_argtypes(Aggref *fc_aggref, Oid *fc_inputTypes)
{
	int			fc_numArguments = 0;
	ListCell   *fc_lc;

	Assert(list_length(fc_aggref->aggargtypes) <= FUNC_MAX_ARGS);

	foreach(fc_lc, fc_aggref->aggargtypes)
	{
		fc_inputTypes[fc_numArguments++] = lfirst_oid(fc_lc);
	}

	return fc_numArguments;
}

/*
 * resolve_aggregate_transtype
 *	识别聚合调用的转换状态值的数据类型。
 *
 * 此函数解析多态聚合的状态数据类型。
 * 必须传入聚合目录条目的 aggtranstype，以及由 get_aggregate_argtypes 提取的实际参数类型。
 * （我们可以在内部获取 pg_aggregate.aggtranstype，但所有现有的调用者
 * 都已经手头有该值，因此我们让他们传递它。）
 */
Oid resolve_aggregate_transtype(Oid fc_aggfuncid,
							Oid fc_aggtranstype,
							Oid *fc_inputTypes,
							int fc_numArguments)
{
	/* 解析过渡状态的实际类型，如果是多态的 */
	if (IsPolymorphicType(fc_aggtranstype))
	{
		/* 必须获取聚合的声明输入类型... */
		Oid		   *fc_declaredArgTypes;
		int			fc_agg_nargs;

		(void) get_func_signature(fc_aggfuncid, &fc_declaredArgTypes, &fc_agg_nargs);

		/*
		 * VARIADIC ANY 聚合可能有比声明的参数更多的实际参数，但
		 * 这些额外的参数不会影响多态类型解析。
		 */
		Assert(fc_agg_nargs <= fc_numArguments);

		fc_aggtranstype = enforce_generic_type_consistency(fc_inputTypes,
														fc_declaredArgTypes,
														fc_agg_nargs,
														fc_aggtranstype,
														false);
		pfree(fc_declaredArgTypes);
	}
	return fc_aggtranstype;
}

/*
 * 为聚合的转换函数创建一个表达式树。
 * 这需要使多态函数可以在聚合中使用——如果没有表达式树，这些函数
 * 不知道它们应该使用的数据类型。（不过，这些树不会被实际执行，因此
 * 我们可以在正确性上稍微放宽。）
 *
 * agg_input_types 和 agg_state_type 识别聚合的输入类型。
 * 这些应该解析为实际类型（即，不应该有 ANYELEMENT 等）。
 * agg_input_collation 是聚合函数的输入排序。
 *
 * 对于有序集聚合，请记住，agg_input_types 描述的是直接参数，后面跟着聚合参数。
 *
 * transfn_oid 和 invtransfn_oid 识别要调用的函数；然而，后者可能是 InvalidOid，但
 * 如果设置了 invtransfn_oid，则 transfn_oid 也必须设置。
 *
 * transfn_oid 也可以在 aggcombinefn 中传递，当 *transfnexpr
 * 被用于一个合并聚合阶段时。我们希望在这种情况下 invtransfn_oid 为
 * InvalidOid，因为没有逆合并函数的概念。
 *
 * 构造的树的指针被返回到 *transfnexpr，
 * *invtransfnexpr。如果没有 invtransfn，则相应的指针被设置为 NULL。
 * 由于使用 invtransfn 是可选的，可以为 invtransfnexpr 传递 NULL。
 */
void build_aggregate_transfn_expr(Oid *fc_agg_input_types,
							 int fc_agg_num_inputs,
							 int fc_agg_num_direct_inputs,
							 bool fc_agg_variadic,
							 Oid fc_agg_state_type,
							 Oid fc_agg_input_collation,
							 Oid fc_transfn_oid,
							 Oid fc_invtransfn_oid,
							 Expr **fc_transfnexpr,
							 Expr **fc_invtransfnexpr)
{
	List	   *fc_args;
	FuncExpr   *fc_fexpr;
	int			fc_i;

	/*
	 * 构建用于 transfn FuncExpr 节点的参数列表。
	 */
	fc_args = list_make1(fc_make_agg_arg(fc_agg_state_type, fc_agg_input_collation));

	for (fc_i = fc_agg_num_direct_inputs; fc_i < fc_agg_num_inputs; fc_i++)
	{
		fc_args = lappend(fc_args,
					   fc_make_agg_arg(fc_agg_input_types[fc_i], fc_agg_input_collation));
	}

	fc_fexpr = makeFuncExpr(fc_transfn_oid,
						 fc_agg_state_type,
						 fc_args,
						 InvalidOid,
						 fc_agg_input_collation,
						 COERCE_EXPLICIT_CALL);
	fc_fexpr->funcvariadic = fc_agg_variadic;
	*fc_transfnexpr = (Expr *) fc_fexpr;

	/*
	 * 如果需要，构建 invtransfn 表达式，参数与 transfn 相同
	 */
	if (fc_invtransfnexpr != NULL)
	{
		if (OidIsValid(fc_invtransfn_oid))
		{
			fc_fexpr = makeFuncExpr(fc_invtransfn_oid,
								 fc_agg_state_type,
								 fc_args,
								 InvalidOid,
								 fc_agg_input_collation,
								 COERCE_EXPLICIT_CALL);
			fc_fexpr->funcvariadic = fc_agg_variadic;
			*fc_invtransfnexpr = (Expr *) fc_fexpr;
		}
		else
			*fc_invtransfnexpr = NULL;
	}
}

/*
 * 类似于 build_aggregate_transfn_expr，但为聚合的序列化函数创建表达式树。
 */
void build_aggregate_serialfn_expr(Oid fc_serialfn_oid,
							  Expr **fc_serialfnexpr)
{
	List	   *fc_args;
	FuncExpr   *fc_fexpr;

	
/* serialfn 始终接受 INTERNAL 并返回 BYTEA */
	fc_args = list_make1(fc_make_agg_arg(INTERNALOID, InvalidOid));

	fc_fexpr = makeFuncExpr(fc_serialfn_oid,
						 BYTEAOID,
						 fc_args,
						 InvalidOid,
						 InvalidOid,
						 COERCE_EXPLICIT_CALL);
	*fc_serialfnexpr = (Expr *) fc_fexpr;
}

/*
 * 像 build_aggregate_transfn_expr 一样，但创建聚合的
 * 反序列化函数的表达式树。
 */
void build_aggregate_deserialfn_expr(Oid fc_deserialfn_oid,
								Expr **fc_deserialfnexpr)
{
	List	   *fc_args;
	FuncExpr   *fc_fexpr;

	/* deserialfn 始终接受 BYTEA、INTERNAL 并返回 INTERNAL */
	fc_args = list_make2(fc_make_agg_arg(BYTEAOID, InvalidOid),
					  fc_make_agg_arg(INTERNALOID, InvalidOid));

	fc_fexpr = makeFuncExpr(fc_deserialfn_oid,
						 INTERNALOID,
						 fc_args,
						 InvalidOid,
						 InvalidOid,
						 COERCE_EXPLICIT_CALL);
	*fc_deserialfnexpr = (Expr *) fc_fexpr;
}

/*
 * 像 build_aggregate_transfn_expr 一样，但创建聚合的
 * 最终函数的表达式树，而不是过渡函数。
 */
void build_aggregate_finalfn_expr(Oid *fc_agg_input_types,
							 int fc_num_finalfn_inputs,
							 Oid fc_agg_state_type,
							 Oid fc_agg_result_type,
							 Oid fc_agg_input_collation,
							 Oid fc_finalfn_oid,
							 Expr **fc_finalfnexpr)
{
	List	   *fc_args;
	int			fc_i;

	/*
	 * 为最终函数构建表达式树
	 */
	fc_args = list_make1(fc_make_agg_arg(fc_agg_state_type, fc_agg_input_collation));

	/* finalfn 可能接受额外的参数，这些参数与聚合的输入类型匹配 */
	for (fc_i = 0; fc_i < fc_num_finalfn_inputs - 1; fc_i++)
	{
		fc_args = lappend(fc_args,
					   fc_make_agg_arg(fc_agg_input_types[fc_i], fc_agg_input_collation));
	}

	*fc_finalfnexpr = (Expr *) makeFuncExpr(fc_finalfn_oid,
										 fc_agg_result_type,
										 fc_args,
										 InvalidOid,
										 fc_agg_input_collation,
										 COERCE_EXPLICIT_CALL);
	/* finalfn 当前从未被视为可变参数 */
}

/*
 * 方便函数，用于为聚合构建虚拟参数表达式。
 *
 * 我们实际上只关心聚合支持函数能够在运行时使用 get_fn_expr_argtype() 
 * 发现其实际参数类型，因此使用与任何真实参数不对应的参数节点是可以的。
 */
static Node * fc_make_agg_arg(Oid fc_argtype, Oid fc_argcollation)
{
	Param	   *fc_argp = makeNode(Param);

	fc_argp->paramkind = PARAM_EXEC;
	fc_argp->paramid = -1;
	fc_argp->paramtype = fc_argtype;
	fc_argp->paramtypmod = -1;
	fc_argp->paramcollid = fc_argcollation;
	fc_argp->location = -1;
	return (Node *) fc_argp;
}
